Fix double-close race condition when handling dead clients #16
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #13
Amp generated PR description:
When a WebSocket client became unresponsive and timed out, the ping timer handler caused a "handle is already closing" error by attempting to close the same TCP handle twice.
The race condition occurred in tcp.lua's ping timeout logic:
Since the write callback hadn't fired yet, the handle appeared not to be closing, so both code paths attempted to close it.
Changes made:
Ping timeout handler (tcp.lua): Removed the call to close_client() for dead clients. Now only calls _remove_client() and on_disconnect() to drop the connection without sending a Close frame. This is correct per RFC 6455, which states code 1006 MUST NOT be sent in a Close frame.
close_client() hardening (client.lua): Made fully defensive:
_remove_client() hardening (tcp.lua): Added explicit state management and a comment explaining that close() is async but marking "closed" immediately is safe since the client is removed from the active list.
Why this implementation is safe:
Amp-Thread-ID: https://ampcode.com/threads/T-eb322254-0c96-4330-ae76-53b06d81f3a3